#define xuser mixc::powerful_cat
#include"concurrency/thread.hpp"
#include"concurrency/thread_self.hpp"
#include"extern/game/snake/snake.hpp"
#include"graphic/draw/rectanglehv.hpp"
#include"io/tty.hpp"
#include"lang/cxx.hpp"
#include"mixc.hpp"
#include"utils/mix_buffer.hpp"

#define inc xuser

constexpr uxx                       max_tick = 10;
constexpr uxx                       ms_per_tick = 40;
inc::snake<128, 128, 2/*两条蛇*/>   g_game;
inc::mix_buffer<char, 4096>         g_buf;

asciis type_img_lut[] = {
    [inc::snake_state_t::empty] = ":::",
    [inc::snake_state_t::next_at_top] = "[ ]",
    [inc::snake_state_t::next_at_bottom] = "[ ]",
    [inc::snake_state_t::next_at_left] = "[ ]",
    [inc::snake_state_t::next_at_right] = "[ ]",
    [inc::snake_state_t::food] = " @ ",
    [inc::snake_state_t::wall] = " # ",
};

xinit(inc::the_main){
    auto new_game           = true;
    auto i_snake            = 0;
    g_game.initial(inc::snake_conf{ .rows = 16, .columns = 16 });

    for(auto i = 0;;){
        auto key            = inc::tty.read_key_non_block();
        auto update         = false;

        // 退出控制
        if (key->has_ctrl and key->value == 'c'){
            break;
        }

        // 方向控制
        switch(key->value()){
        case inc::func_key::top:    g_game.up(i_snake = 0);      break;
        case inc::func_key::bottom: g_game.down(i_snake = 0);    break;
        case inc::func_key::left:   g_game.left(i_snake = 0);    break;
        case inc::func_key::right:  g_game.right(i_snake = 0);   break;

        case 'w': g_game.up(i_snake = 1);    break;
        case 's': g_game.down(i_snake = 1);  break;
        case 'a': g_game.left(i_snake = 1);  break;
        case 'd': g_game.right(i_snake = 1); break;
        }

        // 全局 step
        if (not new_game and i-- == 0){
            i               = max_tick;
            new_game        = g_game.next_term() == bstate_t::fail;
            update          = true;
        }

        // 个体 step，按下按键时候就会触发，如果全局更新过了，就不再更新个体
        else if (key->value() != '\0'){
            new_game        = g_game.next_term(i_snake) == bstate_t::fail;
            update          = true;
        }

        if (new_game){
            new_game        = false;
            update          = true;
            g_game.clear();
            g_game.set_snake();

            // inc::draw::rectanglehv(g_game->columns, g_game->rows, [&](ixx x, ixx y){
            //     g_game.set(x, y, inc::snake_state_t::wall);
            //     xhint(x, y);
            // });

            g_game.set_food();
        }

        if (update){
            update          = false;

            for(uxx y = 0; y < g_game->rows; y++){
                for(uxx x = 0; x < g_game->columns; x++){
                    auto i_type = g_game.get(x, y);
                    g_buf.push(type_img_lut[i_type]);
                }
                g_buf.push(xlocal_endl);
            }

            // 清除画面
            inc::tty.clear();

            // 绘制
            g_buf.foreach_level([](auto seq){
                auto content = inc::c08(seq);
                inc::tty.write(content);
            });

            g_buf.clear();
        }

        inc::thread_self::sleep(ms_per_tick);
    }
};
